﻿/*
 * @Author       : xiaoyuan-cloud 1805980417@qq.com
 * @Date         : 2024-10-21 09:55:09
 * @LastEditors  : xiaoyuan-cloud 1805980417@qq.com
 * @LastEditTime : 2024-10-24 14:54:52
 * @FilePath     : \charger_controller\packages\SAE_J1939\src\inc\J1939.h
 * @Description  : SAE_J1939协议栈
 * SPDX-License-Identifier: MIT
 * Copyright (c) 2024 by xiaoyuan-cloud, All Rights Reserved.
 */
#ifndef _J1939_H
#define _J1939_H

 //----------------------------------类型定义
typedef long unsigned int j1939_uint32_t;
typedef int j1939_int32_t;
typedef unsigned short j1939_uint16_t;
typedef unsigned char j1939_uint8_t;
typedef char j1939_int8_t;
///---------------------------------END

//----------------------------------宏定义
/*参数定义*/
#define J1939_MSG_LENGTH 9              // 消息长度
#define J1939_DATA_LENGTH 8             // 数据长度
#define J1939_TP_MAX_MESSAGE_LENGTH 240 // TP最大接收发送消息长度(最大可配置为1785)

#define J1939_QUEUE_SIZE 10 // 数据缓存队列长度

/*TP的超时时间，单位（ms）*/
#define J1939_TP_T1 750             // 定义TP数据包接收间超时时间
#define J1939_TP_T2 1250            // 定义TP连接管理超时时间
#define J1939_TP_T3 1250            // 宏定义TP的超时时间
#define J1939_TP_T4 1050            // 宏定义TP的超时时间
#define J1939_TP_TIMEOUT_NORMAL 0   // 未超时正常
#define J1939_TP_TIMEOUT_ABNORMAL 1 // 超时

/*TP_CM控制字定义*/
#define J1939_RTS_CONTROL_BYTE 16    // TP.CM_RTS  请求发送
#define J1939_CTS_CONTROL_BYTE 17    // TP.CM_CTS  应答发送
#define J1939_ACK_CONTROL_BYTE 19    // TP.CM_ACK  结束应答
#define J1939_ABORT_CONTROL_BYTE 255 // TP.CM_ABORT  连接中断控制字节（放弃连接）
#define J1939_BAM_CONTROL_BYTE 32    // 广播公告消息

/*J1939 默认的优先级（参考J1939文档）*/
#define J1939_CONTROL_PRIORITY 0x03     // J1939文档默认的优先级
#define J1939_INFO_PRIORITY 0x06        // J1939文档默认的优先级
#define J1939_PROPRIETARY_PRIORITY 0x06 // J1939文档默认的优先级
#define J1939_REQUEST_PRIORITY 0x06     // J1939文档默认的优先级
#define J1939_ACK_PRIORITY 0x06         // J1939文档默认的优先级
#define J1939_TP_CM_PRIORITY 0x07       // J1939文档默认的优先级
#define J1939_TP_DT_PRIORITY 0x07       // J1939文档默认的优先级

#define J1939_NULL     0
///---------------------------------END

//----------------------------------枚举
/*函数返回状态枚举*/
typedef enum
{
    RC_SUCCESS = 0,     // 成功
    RC_ERROR = -1,      // 失败
    RC_PARAMERROR = -2, // 参数错误
    RC_QUEUEEMPTY = -3, // 队列为空
} FUN_RET_STATE;

/*端口枚举*/
typedef enum
{
    Select_CAN_NODE_Null, // 不选择任何CAN硬件
    Select_CAN_NODE_1,    // 选择CAN硬件1
    Select_CAN_NODE_2,    // 选择CAN硬件2
    Select_CAN_NODE_3,    // 选择CAN硬件3
    Select_CAN_NODE_4,    // 选择CAN硬件4
} CAN_NODE;

/*组帧PF定义*/
typedef enum
{
    J1939_PF_DT = 235,    // 数据传输
    J1939_PF_TP_CM = 236, // 链接管理
} J1939_TP_PF_ENUM;

/*组帧发送步骤*/
typedef enum
{
    J1939_TP_TX_WAIT,     // 发送空闲
    J1939_TP_TX_CM_START, // 请求连接
    J1939_TP_TX_CM_WAIT,  // 等待连接
    J1939_TP_TX_DT,       // 应答
    J1939_TP_WAIT_ACK,    // 等待ACK应答
    J1939_TP_TX_ERROR,    // 错误
    J1939_TX_DONE,        // 发送完成
} J1939_TP_Tx_Step;

/*组帧接收步骤*/
typedef enum
{
    J1939_TP_RX_WAIT,      // 空闲等待
    J1939_TP_RX_READ_DATA, // 读取数据
    J1939_TP_RX_DATA_WAIT, // 等待数据
    J1939_TP_RX_ERROR,     // TP连接错误
    J1939_RX_DONE,         // TP完成
} J1939_TP_Rx_Step;

/*组帧TP状态描述*/
typedef enum
{
    J1939_TP_NULL,   // 长数据传输处于空闲，只有TP系统处于空闲，才能用处理下一个发送，和接受请求*/
    J1939_TP_RX,     // 长数据传输处于接收
    J1939_TP_TX,     // 长数据传输处于发送
    J1939_TP_OSBUSY, // 长数据传输处于繁忙，比如刚接受一整段长数据，但是CPU没来得处理，又一个长数据请求到来，为了数据不被覆盖，将状态设为本值
} J1939_TP_State;
///---------------------------------END

//----------------------------------J1939消息对象定义
/*单帧消息*/
union J1939_MESSAGE_OBJ
{
    struct
    {
        j1939_uint8_t DataPage : 1;            // 数据页
        j1939_uint8_t Res : 1;                 // Res位
        j1939_uint8_t Priority : 3;            // 优先级
        j1939_uint8_t Reserve : 3;             // 空闲
        j1939_uint8_t PDUFormat;               // PF
        j1939_uint8_t PDUSpecific;             // PS
        j1939_uint8_t SourceAddress;           // SA
        j1939_uint8_t DataLength : 4;          // 数据长度
        j1939_uint8_t RTR : 4;                 // RTR位
        j1939_uint8_t Data[J1939_DATA_LENGTH]; // 数据
        j1939_uint32_t PGN : 24;               // 参数组编号
        j1939_uint8_t ReservePGN : 8;          // 空闲
    } j1939_pid;
    j1939_uint8_t Array[J1939_MSG_LENGTH + J1939_DATA_LENGTH];
};
typedef union J1939_MESSAGE_OBJ J1939_MESSAGE;

/*组帧发送消息*/
typedef struct
{
    struct
    {
        j1939_uint32_t PGN;                              // 参数组编号
        j1939_uint8_t data[J1939_TP_MAX_MESSAGE_LENGTH]; // 数据
        j1939_uint16_t byte_count;                       // 数据大小
        j1939_uint8_t SA;                                // 目标地址
    } tp_tx_msg;                                         // 发送消息对象

    J1939_TP_Tx_Step state; // 组帧发送步骤状态

    j1939_uint16_t tim;                // 时间
    j1939_uint8_t packet_offset_p;     // 数据包偏移指针
    j1939_uint8_t packet_total;        // 数据包总个数
    j1939_uint8_t packets_request_num; // 应答请求数据包数

} J1939_TRANSPORT_TX_INFO;

/*组帧接收消息*/
typedef struct
{
    struct
    {
        j1939_uint32_t PGN;                              // 参数组编号
        j1939_uint8_t data[J1939_TP_MAX_MESSAGE_LENGTH]; // 数据
        j1939_uint16_t byte_count;                       // 数据大小
        j1939_uint8_t SA;                                // 目标地址
    } tp_rx_msg;                                         // 接收消息对象

    J1939_TP_Rx_Step state; // 组帧接收步骤状态

    j1939_uint16_t time;          // 时间
    j1939_uint8_t packets_total;  // 数据包总个数
    j1939_uint8_t packets_ok_num; // 已接收数据包个数
} J1939_TRANSPORT_RX_INFO;

/*组帧数据转存*/
typedef struct
{
    j1939_uint8_t* data;       // 缓存区指针
    j1939_uint16_t data_num;   // 缓存区大小
    j1939_uint8_t SA;          // 组帧接收 源地址
    j1939_uint16_t byte_count; // 组帧接收 数据大小
    j1939_uint32_t PGN;        // 组帧接收 PGN
} TP_RX_MESSAGE;

/*组帧TP状态标志*/
typedef struct
{
    J1939_TP_State state;    // TP连接状态
    CAN_NODE TP_RX_CAN_NODE; // TP接收请求 CAN硬件端口
    CAN_NODE TP_TX_CAN_NODE; // TP发送请求 CAN硬件端口
} J1939_TP_Flags;
///---------------------------------END

// TP协议心跳入口
void J1939_TP_Poll(CAN_NODE port, j1939_uint16_t dt_ms);
// 报文发送轮询入口
void J1939_Poll(void);
// 中断消息读取处理入口
void J1939_ISR(CAN_NODE port);

// 协议栈初始化
void J1939_Init(void);
// 单帧消息
j1939_uint8_t J1939_Send_Message(J1939_MESSAGE* pthis, CAN_NODE port);
j1939_uint8_t J1939_Read_Message(J1939_MESSAGE* pthis, CAN_NODE port);
// 组帧消息
j1939_uint8_t J1939_TP_TX_Message(j1939_uint32_t PGN, j1939_uint8_t SA, j1939_uint8_t* data, j1939_uint16_t data_num, CAN_NODE port);
j1939_uint8_t J1939_TP_RX_Message(TP_RX_MESSAGE* pthis, CAN_NODE port);
#endif // !_J1939_H
